package com.carrot.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.carrot.common.core.domain.dto.PointDataDto;
import com.carrot.common.core.domain.entity.*;
import com.carrot.common.core.domain.vo.StationCellPointDataVo;
import com.carrot.common.enums.MatchTypeEnum;
import com.carrot.common.enums.OnlineEnableEnum;
import com.carrot.common.exception.ServiceException;
import com.carrot.common.utils.StringUtils;
import com.carrot.common.utils.WrapperUtil;
import com.carrot.system.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 场站 业务层处理
 *
 * @author liuhongzhen
 */
@Service
public class StationPointServiceImpl implements IStationPointService {

    private static final Logger log = LoggerFactory.getLogger(StationPointServiceImpl.class);

    @Autowired
    private ISysPointHistoryMapService historyMapService;
    @Autowired
    private ISysPointStandardFieldService standardFieldService;
    @Autowired
    private ISysPointUnitMapService unitMapService;
    @Autowired
    private ISysStationService stationService;
    @Autowired
    private ISysStationCellTypeService stationCellTypeService;
    @Autowired
    private ISysPointEquipmentService pointEquipmentService;
    @Autowired
    private ISysPointService pointService;

    /**
     * 导入用户数据
     *
     * @param stationId   场站ID
     * @param dataList    数据列表
     * @param operateName 操作用户
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public String importPointData(
            String stationId, List<PointDataDto> dataList, String operateName) {

        if (StringUtils.isNull(dataList) || dataList.isEmpty()) {
            throw new ServiceException("导入点表数据不能为空！");
        }
        // 读取场站的配置
        final SysStation station = stationService.selectStationByStationId(stationId);
        if (null == station) {
            throw new ServiceException("导入点表数据，场站不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();

        List<PointDataDto> nonCellData =
                dataList.stream()
                        .filter(it -> !"cell".equals(it.getEquipmentType()))
                        .collect(Collectors.toList());

        List<SysPoint> allDataList = Lists.newArrayList();
        List<SysPoint> nonCellDataList = createNonCellPointData(station, nonCellData);
        if (!nonCellDataList.isEmpty()) {
            allDataList.addAll(nonCellDataList);
        }
        // 单体
        List<PointDataDto> cellData =
                dataList.stream()
                        .filter(it -> "cell".equals(it.getEquipmentType()))
                        .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(cellData)) {
            List<SysPoint> cellDataList = createCellPointData(station, cellData);
            if (!cellDataList.isEmpty()) {
                allDataList.addAll(cellDataList);
            }
        }
        try {
            // 导入数据
            if (CollUtil.isNotEmpty(allDataList)) {
                // 先删除场站的点表数据
                UpdateWrapper<SysPoint> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("station_id", stationId);
                pointService.remove(updateWrapper);
                pointService.saveBatch(allDataList);

                //todo 先按照列表获取设备列表，后面优化
                // 按照设备id分组
                List<SysPointEquipment> pointEquipments = Lists.newArrayList();
                Map<String, List<SysPoint>> sysPointMap = allDataList.stream()
                        .collect(Collectors.groupingBy(SysPoint::getEquipmentId));

                sysPointMap.forEach((equipmentId, list) -> {
                    SysPoint point = list.get(0);

                    SysPointEquipment pointEquipment = new SysPointEquipment();
                    pointEquipment.setStationId(station.getStationId());
                    pointEquipment.setEquipmentType(point.getEquipmentType());
                    pointEquipment.setEquipmentId(point.getEquipmentId());
                    pointEquipment.setDeleted(0);

                    pointEquipments.add(pointEquipment);
                });

                pointEquipmentService.addPointEquipment(stationId, pointEquipments);
            }
            successMsg.append("<br/>").append(allDataList.size()).append("、导入成功");
        } catch (Exception e) {
            failureNum++;
            String msg = "<br/>" + failureNum + "、导入失败：";
            failureMsg.append(msg).append(e.getMessage());
            log.error(msg, e);
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + allDataList.size() + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * 生成非单体的点表数据
     */
    private List<SysPoint> createNonCellPointData(
            SysStation station, List<PointDataDto> nonCellData) {

        String stationId = station.getStationId();
        String protocolName = station.getStationAlias();
        // 系数
        String factor = null == station.getFactor() ? "1" : station.getFactor();
        // 偏移量
        String constant = null == station.getConstant() ? "0" : station.getConstant();
        // 表达式
        String expression = StringUtils.isEmpty(station.getExpression()) ? "" : station.getExpression();

        Map<String, List<String>> historyFieldDict = getHistoryFieldDict();
        Map<String, String> unitDict = getUnitDict();
        Map<String, SysPointStandardField> standardFieldDict = getStandardFieldDict();

        List<SysPoint> list = Lists.newArrayList();
        for (PointDataDto row : nonCellData) {
            // 设备类型
            String equipmentType = row.getEquipmentType();
            // 生成equipment_id
            String equipmentId = protocolName + "_" + equipmentType;
            // 描述
            String description = row.getDescription();
            // 单位
            String unit = row.getUnit();

            String historyKey = equipmentType + "_" + description.replace(" ", "");
            String mapField = "";
            String matchType = "0";
            if (historyFieldDict.containsKey(historyKey)) {
                List<String> historyFieldList = historyFieldDict.get(historyKey);
                // 字段去重
                historyFieldList = historyFieldList.stream().distinct().collect(Collectors.toList());
                if (historyFieldList.size() == 1) {
                    mapField = historyFieldList.get(0);
                    matchType = "1";
                } else {
                    mapField = String.join(",", historyFieldList);
                    matchType = "2";
                }
            }
            // standard_unit, property_name, remark, result_type
            String standardUnit = "";
            String propertyName = "";
            String remark = "";
            String resultType = "";
            String standardDescription = "";

            if ("1".equals(matchType)) {
                String standardFieldKey = equipmentType + "_" + mapField;
                if (standardFieldDict.containsKey(standardFieldKey)) {
                    SysPointStandardField standardField = standardFieldDict.get(standardFieldKey);
                    standardUnit = standardField.getStandardUnit();
                    propertyName = standardField.getPropertyName();
                    remark = standardField.getRemark();
                    resultType = standardField.getResultType();
                    standardDescription = standardField.getDescription();
                }
            }
            // 系数
            if (StringUtils.isNotEmpty(unit) && StringUtils.isNotEmpty(standardUnit)) {
                String lowerUnit = unit.toLowerCase() + "_" + standardUnit.toLowerCase();
                factor = unitDict.get(lowerUnit);
            }
            SysPoint sysPoint = new SysPoint();
            sysPoint.setStationId(stationId);
//            sysPoint.setDataset(row.getDataset());
            sysPoint.setInfoObjAddr(row.getInfoObjAddr());
            sysPoint.setProtocolName(protocolName);
            sysPoint.setPropertyName(propertyName);
            sysPoint.setEquipmentType(equipmentType);
            sysPoint.setEquipmentId(equipmentId);
            sysPoint.setFactor(factor);
            sysPoint.setConstant(constant);
            sysPoint.setExpression("");
            sysPoint.setUdf("");
            sysPoint.setResultType(resultType);
            sysPoint.setStandardDescription(standardDescription);
            sysPoint.setDescription(description);
            sysPoint.setComment(row.getComment());
            sysPoint.setUnit(unit);
            sysPoint.setExpression(expression);
            sysPoint.setOnlineEnable(OnlineEnableEnum.DISABLE.getValue());
            sysPoint.setMapField(mapField);
            sysPoint.setRemark(remark);
            sysPoint.setInitPropertyName(propertyName);
            sysPoint.setFillData("0");
            sysPoint.setMatchType(matchType);
            sysPoint.setDeleted(0);

            list.add(sysPoint);
        }
        return list;
    }

    /**
     * 生成单体的点表数据 电池簇和单体关联 电压、电流、电阻、温度、soc、soh
     *
     * @param station      场站
     * @param cellDataList 单体数据
     */
    private List<SysPoint> createCellPointData(SysStation station, List<PointDataDto> cellDataList) {

        String stationId = station.getStationId();
        String stationAlias = station.getStationAlias();
        // 系数
        String factor = null == station.getFactor() ? "1" : station.getFactor();
        // 偏移量
        String constant = null == station.getConstant() ? "0" : station.getConstant();
        // 表达式
        String expression = StringUtils.isEmpty(station.getExpression()) ? "" : station.getExpression();

        Map<String, PointDataDto> cellDataMap =
                cellDataList.stream()
                        .collect(Collectors.toMap(PointDataDto::getDescription, Function.identity()));

        // 电池簇的个数
        int clusterNum = 1;

        Map<String, List<String>> historyFieldDict = getHistoryFieldDict();
        Map<String, String> unitDict = getUnitDict();
        Map<String, SysPointStandardField> standardFieldDict = getStandardFieldDict();

        List<SysPoint> pointList = Lists.newArrayList();

        for (int no = 1; no <= clusterNum; no++) {
            String clusterNo = String.valueOf(no);
            List<StationCellPointDataVo> stationCellPointDataList = stationCellTypeService.getCellPointData(stationId, stationAlias,
                    clusterNo, cellDataMap);
            // 转成标准点表的单位
            for (StationCellPointDataVo pointDataVo : stationCellPointDataList) {
                // 设备类型
                String equipmentType = pointDataVo.getEquipmentType();
//                String equipmentId = protocolName + "_" + equipmentType + startNo;
                String description = pointDataVo.getDescription();
                String historyKey = equipmentType + "_" + description.replace(" ", "");
                // 单位
                String unit = pointDataVo.getUnit();

                String mapField = "";
                String reflectionType = "0";
                if (historyFieldDict.containsKey(historyKey)) {
                    List<String> historyFieldList = historyFieldDict.get(historyKey);
                    // 字段去重
                    historyFieldList = historyFieldList.stream().distinct().collect(Collectors.toList());
                    if (historyFieldList.size() == 1) {
                        mapField = historyFieldList.get(0);
                        reflectionType = "1";
                    } else {
                        mapField = String.join(",", historyFieldList);
                        reflectionType = "2";
                    }
                }
                // standard_unit, property_name, remark, result_type
                String standardUnit = "";
                String propertyName = "";
                String remark = "";
                String resultType = "";
                String standardDescription = "";

                if (MatchTypeEnum.ONE.getValue().equals(reflectionType)) {
                    String standardFieldKey = equipmentType + "_" + mapField;
                    if (standardFieldDict.containsKey(standardFieldKey)) {
                        SysPointStandardField standardField = standardFieldDict.get(standardFieldKey);
                        standardUnit = standardField.getStandardUnit();
                        propertyName = standardField.getPropertyName();
                        remark = standardField.getRemark();
                        resultType = standardField.getResultType();
                        standardDescription = standardField.getDescription();
                    }
                }
                // 系数
                if (StringUtils.isNotEmpty(unit) && StringUtils.isNotEmpty(standardUnit)) {
                    String lowerUnit = unit.toLowerCase() + "_" + standardUnit.toLowerCase();
                    factor = unitDict.get(lowerUnit);
                }
                pointDataVo.setPropertyName(propertyName);
                pointDataVo.setRemark(remark);
                pointDataVo.setResultType(resultType);
                pointDataVo.setStandardDescription(standardDescription);
                pointDataVo.setFactor(factor);
                pointDataVo.setConstant(constant);
                pointDataVo.setExpression(expression);
                pointDataVo.setDeleted(0);

                pointList.add(WrapperUtil.transform(pointDataVo, SysPoint.class));
            }
        }

        return pointList.stream().filter(item -> !item.getInfoObjAddr().isEmpty()).collect(Collectors.toList());
    }

    /**
     * 历史字段的映射
     */
    private Map<String, List<String>> getHistoryFieldDict() {
        List<SysPointHistoryMap> list = historyMapService.list();
        Map<String, List<String>> historyFieldDict = Maps.newHashMap();
        for (SysPointHistoryMap line : list) {
            String key = line.getEquipmentType() + "_" + line.getDescription();
            if (historyFieldDict.containsKey(key)) {
                List<String> fieldList = historyFieldDict.get(key);
                fieldList.add(line.getMapField());
                historyFieldDict.put(key, fieldList);
            } else {
                List<String> fieldList = Lists.newArrayList();
                fieldList.add(line.getMapField());
                historyFieldDict.put(key, fieldList);
            }
        }
        return historyFieldDict;
    }

    /**
     * 单位映射
     */
    private Map<String, String> getUnitDict() {

        List<SysPointUnitMap> list = unitMapService.list();
        Map<String, String> unitMap = Maps.newHashMap();
        for (SysPointUnitMap line : list) {
            String key = line.getOtherUnit() + "_" + line.getUnit();
            unitMap.put(key, line.getFactor());
        }
        return unitMap;
    }

    /**
     * 标准字段映射
     */
    private Map<String, SysPointStandardField> getStandardFieldDict() {

        List<SysPointStandardField> list = standardFieldService.list();
        Map<String, SysPointStandardField> standardFieldMap = Maps.newHashMap();
        for (SysPointStandardField line : list) {
            String key = line.getEquipmentType() + "_" + line.getMapField();
            standardFieldMap.put(key, line);
        }
        return standardFieldMap;
    }
}
